package com.zyc.auto;

import com.zyc.pojo.Table;
import com.zyc.pojo.TableProperty;
import com.zyc.util.HappyUtil;

import java.io.*;
import java.util.List;

/**
 * 用于制作Add.html和Edit.html的类
 * author RWdaze
 */
public class AutoAddEdit {
    /**
     * 目标文件夹
     */
    private final String targetPath;
    /**
     * layui.css的路径
     */
    private final String layuiCss;
    /**
     * public.css的路径
     */
    private final String publicCss;
    /**
     * layui.js的路径
     */
    private final String layuiJs;
    /**
     * constantUtil的路径
     */
    private final String constantUtilPath;

    /**
     * 构造函数，用来初始化一些属性
     */
    public AutoAddEdit() {
        targetPath = HappyUtil.properties.getProperty("targetPath");
        layuiCss = HappyUtil.properties.getProperty("layuiCss");
        publicCss = HappyUtil.properties.getProperty("publicCss");
        layuiJs = HappyUtil.properties.getProperty("layuiJs");
        constantUtilPath = HappyUtil.properties.getProperty("constantUtil");
    }

    /**
     * 生成add.html和edit.html文件的函数入口
     * 这个函数将自动在目标文件夹下的/pages/add文件夹和/pages/edit文件夹内
     * 生成的文件名为 [pojo名小驼峰] + Add.html 和 [pojo名小驼峰] + Edit.html
     */
    public void start() throws IOException {
        //获取目标数据库中的所有表名
        List<Table> tableList = HappyUtil.getTableList();
        //遍历所有表名
        for (Table table : tableList) {
            //根据每张表，获取表中所有的字段
            //生成add.html文件
            produceAdd(table);
            //生成edit.html文件
            produceEdit(table);
        }
    }

    /**
     * 根据传入的DataInfo对象，在目标文件夹中生成一个add.html文件
     *
     * @param table 表名
     */
    private void produceAdd(Table table) throws IOException {
        //获取表的小驼峰名称
        String lowerCamelName = table.getTableLowerCamelName();
        //获取属性名，这里获取的就是小驼峰命名法的属性名
        String addHtmlPath = targetPath + "\\pages\\add\\" + lowerCamelName + "Add.html";
        //如果目标文件夹不存在，则创建目录
        File addHtmlDir = new File(targetPath + "\\pages\\add");
        if (!addHtmlDir.exists() && !addHtmlDir.mkdirs()) {
            System.err.println("文件夹生成错误！" + addHtmlDir);
            return;
        }
        FileOutputStream fos = new FileOutputStream(addHtmlPath);
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        BufferedWriter bw = new BufferedWriter(osw);
        //写入第一部分 Html的开头部分
        bw.write(getAddHtmlPart1(lowerCamelName + "Add"));
        //循环写入第二部分 表格输入框的部分
        for (TableProperty tableProperty : table.getTableProperties()) {
            bw.write(getAddHtmlPart2(tableProperty));
        }
        //写入第三部分 Html的Js代码开头部分
        bw.write(getAddHtmlPart3());
        //循环写入第四部分 Js中layui渲染日期输入框的部分
        for (TableProperty tableProperty : table.getTableProperties()) {
            if (tableProperty.getJavaType() == null) {
                System.out.println("未知数据库属性!" + tableProperty.getDbType());
            }
            if (tableProperty.getJavaType().equals("Date")) {
                bw.write(getAddHtmlPart4(tableProperty));
            }
        }
        //写入第五部分 最后的结束部分
        bw.write(getAddHtmlPart5(lowerCamelName));
        //写入结束
        bw.flush();
        System.out.println(addHtmlPath);
        HappyUtil.closeAll(bw, osw, fos);
    }

    /**
     * 根据传入的DataInfo对象，在目标文件夹中生成一个edit.html文件
     *
     * @param table 表名
     */
    private void produceEdit(Table table) throws IOException {
        //获取表的驼峰名称
        String lowerCamelName = table.getTableLowerCamelName();
        //获取属性名，这里获取的就是小驼峰命名法的属性名
        String editHtmlPath = targetPath + "\\pages\\edit\\" + lowerCamelName + "Edit.html";
        //如果目标文件夹不存在，则创建目录
        File addHtmlDir = new File(targetPath + "\\pages\\edit");
        if (!addHtmlDir.exists() && !addHtmlDir.mkdirs()) {
            return;
        }
        FileOutputStream fos = new FileOutputStream(editHtmlPath);
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        BufferedWriter bw = new BufferedWriter(osw);
        //写入第一部分 Html的开头部分
        bw.write(getEditHtmlPart1(lowerCamelName + "Edit"));
        //循环写入第二部分 表格输入框的部分
        for (TableProperty tableProperty : table.getTableProperties()) {
            if (tableProperty == table.getPrimaryKey()) {
                //如果是主键，则进行特殊的处理
                bw.write(getEditHtmlPart2Primary(tableProperty));
            } else {
                //这里直接使用add里面的函数。因为需要的内容是一样的
                bw.write(getAddHtmlPart2(tableProperty));
            }
        }
        //写入第三部分 Html的Js代码开头部分
        bw.write(getEditHtmlPart3());
        //循环写入第四部分 Js中layui渲染日期输入框的部分
        for (TableProperty tableProperty : table.getTableProperties()) {
            if (tableProperty.getJavaType().equals("Date")) {
                //这里直接使用add里面的函数。因为需要的内容是一样的
                bw.write(getAddHtmlPart4(tableProperty));
            }
        }
        //写入第五部分 Edit文件特有的回填部分
        bw.write(getEditHtmlPart5(table));
        //写入结束
        bw.flush();
        System.out.println(editHtmlPath);
        HappyUtil.closeAll(bw, osw, fos);
    }


    /**
     * 获得Add.Html文件的第一个公共部分
     * 这是Html的开头固定部分，唯一需要填的也就是标题和一些css，js的路径
     * 因为css，js提前在配置文件设定好了，所以只需要传参标题就能生成第一个部分
     *
     * @param title 这个公共部分包含了标题部分，需要传进来
     * @return Add.Html文件的第一个公共部分
     */
    private String getAddHtmlPart1(String title) {
        return "<!DOCTYPE html>" +
                "<html><head>" +
                "<meta charset=\"utf-8\">" +
                "<title>" + title + "</title><meta name=\"renderer\" content=\"webkit\">" +
                "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">" +
                "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">" +
                "<link rel=\"stylesheet\" href=\"" + layuiCss + "\" media=\"all\">" +
                "<link rel=\"stylesheet\" href=\"" + publicCss + "\" media=\"all\">" +
                "<style>body {background-color: #ffffff;}</style>" +
                "</head><body>" +
                "<div class=\"layui-form layuimini-form\">";
    }

    /**
     * 获得Add.Html文件的第二个公共部分。
     * 它是表中每一个属性所对应的输入框
     * 一般来说这个部分都是需要循环的，每一个属性都需要一个输入框。
     * 因为是属性对应的输入框，所以需要传参DataInfo
     *
     * @param tableProperty 获得这个属性的对象
     * @return Add.Html文件的第二个公共部分
     */
    private String getAddHtmlPart2(TableProperty tableProperty) {
        String comment = tableProperty.getComment();
        String propertyName = tableProperty.getPropertyLowerCamelName();
        return "<div class=\"layui-form-item\">" +
                "<label class=\"layui-form-label required\">" + comment + "</label>" +
                "<div class=\"layui-input-block\">" +
                "<input type=\"text\" name=\"" + propertyName + "\" lay-verify=\"required\" " +
                "lay-reqtext=\"" + comment + "不能为空\" placeholder=\"请输入" + comment + "\" id = \"" +
                propertyName + "\" value=\"\" class=\"layui-input\">" +
                "<tip>填写" + comment + "。</tip>" +
                "</div>" +
                "</div>";
    }

    /**
     * 获得Add.Html文件的第三个公共部分。
     * 一般来说这个部分是结束第二部分的循环，Html页面开始进入Js的编辑的公共部分
     * 因为很固定，所以不需要传参
     *
     * @return Add.Html文件的第三个公共部分
     */
    private String getAddHtmlPart3() {
        return "<div class=\"layui-form-item\"><div class=\"layui-input-block\">" +
                "<button class=\"layui-btn layui-btn-normal\" lay-submit lay-filter=\"saveBtn\">确认添加</button>" +
                "</div></div></div>" +
                "<script src=\"" + layuiJs + "\" charset=\"utf-8\">" +
                "</script>"+
                "<link rel=\"stylesheet\" href=\"" + publicCss + "\" media=\"all\">" +
                "<script>" +
                "layui.use(['form', 'upload', 'layer', 'laydate'], function () {" +
                "var form=layui.form,$=layui.$,laydate=layui.laydate;";
    }

    /**
     * 获得Add.Html文件的第四个公共部分
     * 这个部分是渲染日期用的部分
     * 一般来说这部分都是只有日期类型用到，
     * 所以一般循环判断，如果是日期，则执行该函数
     *
     * @param tableProperty 获得这个属性的对象
     * @return Add.Html文件的第四个公共部分
     */
    private String getAddHtmlPart4(TableProperty tableProperty) {
        String propertyName = tableProperty.getPropertyLowerCamelName();
        return "laydate.render({elem: '#" + propertyName + "',type: 'datetime'});";
    }

    /**
     * 获得Add.Html文件的第五个公共部分
     * 这部分是结尾的部分，但是包含了向后端传递参数的ajax部分
     * 所以需要当前操作的pojo类的类名
     *
     * @param pojoName 获得这个当前表操作的对象名
     * @return Add.Html文件的第四个公共部分
     */
    private String getAddHtmlPart5(String pojoName) {
        return "form.on('submit(saveBtn)', function (data) " +
                "{$.ajax({" +
                "type: \"POST\"," +
                "url: host + \"/" + pojoName + ".do/insert\"," +
                "beforeSend: function(XMLHttpRequest) {\n" +
                "let token = sessionStorage.getItem(\"token\");\n" +
                "XMLHttpRequest.setRequestHeader(\"token\", token);\n" +
                "}," +
                "data: JSON.stringify(data.field)," +
                "contentType: \"application/json\"," +
                "success: function (res) {" +
                "if(res.code == -1004) {\n" +
                "layer.msg(\"身份验证失败，请重新登录\", function() {\n" +
                "location.href = \"../../../index.html\";\n" +
                "});\n" +
                "}\n" +
                "if(res.code != 0) {\n" +
                "layer.msg(res.msg);\n" +
                "}" +
                "var iframeIndex = parent.layer.getFrameIndex(window.name);" +
                "parent.layer.close(iframeIndex);" +
                "}});" +
                "return false;});});" +
                "</script></body></html>";
    }


    /**
     * 获得Edit.Html文件的第一个公共部分
     * 这是Html的开头固定部分，唯一需要填的也就是标题和一些css，js的路径
     * 因为css，js提前在配置文件设定好了，所以只需要传参标题就能生成第一个部分
     *
     * @param title 这个公共部分包含了标题部分，需要传进来
     * @return Edit.Html文件的第一个公共部分
     */
    private String getEditHtmlPart1(String title) {
        return "<!DOCTYPE html>" +
                "<html><head>" +
                "<meta charset=\"utf-8\">" +
                "<title>" + title + "</title>" +
                "<meta name=\"renderer\" content=\"webkit\">" +
                "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">" +
                "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">" +
                "<link rel=\"stylesheet\" href=\"" + layuiCss + "\" media=\"all\">" +
                "<link rel=\"stylesheet\" href=\"" + publicCss + "\" media=\"all\">" +
                "<style>body {background-color: #ffffff;}</style>" +
                "</head><body><div class=\"layui-form layuimini-form\" lay-filter=\"form\">";
    }

    /**
     * 获得Edit.Html文件的第二个主键的公共部分
     * 注意，这个公共部分只适用于主键。
     * 因为循环的部分可以直接用getAddHtmlPart2
     *
     * @param tableProperty 获得这个属性的对象
     * @return Edit.Html文件的第二个公共部分
     */
    private String getEditHtmlPart2Primary(TableProperty tableProperty) {
        String propertyName = tableProperty.getPropertyLowerCamelName();
        return "<div class=\"layui-form-item\">" +
                "<div class=\"layui-input-block\">" +
                "<input type=\"hidden\" name=\"" + propertyName + "\" id=\"" + propertyName + "\">" +
                "</div>" +
                "</div>";
    }

    /**
     * 获得Edit.Html文件的第三个公共部分。
     * 一般来说这个部分是结束第二部分的循环，Html页面开始进入Js的编辑的公共部分
     * 因为很固定，所以不需要传参
     *
     * @return Edit.Html文件的第三个公共部分
     */
    private String getEditHtmlPart3() {
        return "<div class=\"layui-form-item\">" +
                "<div class=\"layui-input-block\">" +
                "<button class=\"layui-btn layui-btn-normal\" lay-submit lay-filter=\"saveBtn\">确认保存</button>" +
                "</div></div></div>" +
                "<script src=\"" + layuiJs + "\" charset=\"utf-8\"></script>" +
                "<script src=\"" + constantUtilPath + "\" charset=\"utf-8\"></script>" +
                "<script>" +
                "layui.use(['form', 'upload', 'laydate'], function () {" +
                "var form = layui.form,$ = layui.$,laydate = layui.laydate;";
    }

    /**
     * 获得Edit.Html文件的第五个公共部分。
     * 这个部分是从后端获得数据并且回填的部分
     * 直接完成了判断主键和循环的部分，这样写虽然有一点点不符合之前的规范
     * 但是实际上可以减少两个部分的代码，增加可读性。
     *
     * @param table 属性列表
     * @return Edit.html的第五个公共部分
     */
    private String getEditHtmlPart5(Table table) {
        String primaryKey = table.getPrimaryKey().getPropertyLowerCamelName();
        String pojoName = table.getTableLowerCamelName();
        StringBuilder part5 = new StringBuilder("var " + primaryKey + " = localStorage.getItem(\"" + primaryKey + "\");" +
                "$.ajax({" +
                "type:\"GET\"," +
                "url: host + \"/" + pojoName + ".do/selectById?" + primaryKey + "=\" + " + primaryKey + "," +
                "beforeSend: function(XMLHttpRequest) {\n" +
                "let token = sessionStorage.getItem(\"token\");\n" +
                "XMLHttpRequest.setRequestHeader(\"token\", token);\n" +
                "},\n"+
                "success: function (res) {" +
                "if(res.code == -1004) {\n" +
                "layer.msg(\"身份验证失败，请重新登录\", function() {\n" +
                "location.href = \"../../../index.html\";\n" +
                "});\n" +
                "}\n" +
                "if(res.code != 0) {\n" +
                "layer.msg(res.msg);\n" +
                "}" +
                "if (res.code === 0) {" +
                "var pojoData = res.data;" +
                "form.val('form', {");
        boolean sign = true;
        for (TableProperty tableProperty : table.getTableProperties()) {
            if (sign) {
                sign = false;
            } else {
                part5.append(",");
            }
            String propertyName = tableProperty.getPropertyLowerCamelName();
            part5.append("\"").append(propertyName).append("\": pojoData.").append(propertyName);
        }
        part5.append("});localStorage.clear();}}});" +
                "form.on('submit(saveBtn)', function (data) {" +
                "$.ajax({type:\"POST\"," + "url: host + \"/").append(pojoName).append(".do/update\",")
                .append("data: JSON.stringify(data.field)," +
                        "contentType:\"application/json\"," +
                        "beforeSend: function(XMLHttpRequest) {\n" +
                        "let token = sessionStorage.getItem(\"token\");\n" +
                        "XMLHttpRequest.setRequestHeader(\"token\", token);\n" +
                        "}," +
                        "success: function (res) {" +
                        "if(res.code == -1004) {\n" +
                        "layer.msg(\"身份验证失败，请重新登录\", function() {\n" +
                        "location.href = \"../../../index.html\";\n" +
                        "});\n" +
                        "}\n" +
                        "if(res.code != 0) {\n" +
                        "layer.msg(res.msg);\n" +
                        "}" +
                        "var iframeIndex = parent.layer.getFrameIndex(window.name);" +
                        "parent.layer.close(iframeIndex);}});" +
                        "return false;});});" +
                        "</script></body></html>");
        return part5.toString();
    }
}
